package com.simpleplayer.MediaPlayer;

import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.ViewGroup;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;

import com.simpleplayer.contentview.ContentView;
import com.simpleplayer.contentview.ContentViewFactory;
import com.simpleplayer.engine.PlayerEngine;
import com.simpleplayer.engine.PlayerEngineClient;
import com.simpleplayer.engine.PlayerEngineFactory;
import com.simpleplayer.services.LogUtil;
import com.simpleplayer.services.Timer;
import com.simpleplayer.views.videoview.VideoView;

public class SimplePlayer extends BasePlayer implements AudioManager.OnAudioFocusChangeListener {

    private static final String TAG = "SimplePlayer";

    public static interface BandwidthCallback {
        /**
         * called when get bandwidth
         * @param bitrateEstimate estimated bitrate, unit: byte/s
         */
        public void onGetBandwidth(long bitrateEstimate);
    }

    // 显示模式
    @IntDef({UNDEFINEMODE, INLINE, FLOATWINDOW, FULLSCREEN})
    public @interface DISPLAYMODE {}

    // 视频引擎
    @IntDef({ExoPlayer, AndroidMediaPlayer, IjkPlayer})
    public @interface ENGINETYPE {}

    // 绘制 surface 的 view
    @IntDef({VIEW_TYPE_SurfaceView, VIEW_TYPE_TextureView, VIEW_TYPE_GLSurfaceView})
    public @interface VIEWTYPE {}

    // 使用 GLSurfaceView 时的 renderer
    @IntDef({DIRECT, SPHERE})
    public @interface RENDERTYPE {}

    public static final int UNDEFINEMODE = VideoView.UNDEFINEMODE;
    public static final int INLINE = VideoView.INLINE;
    public static final int FLOATWINDOW = VideoView.FLOATWINDOW;
    public static final int FULLSCREEN = VideoView.FULLSCREEN;

    public static final int ExoPlayer = PlayerEngine.ExoPlayer;
    public static final int AndroidMediaPlayer = PlayerEngine.AndroidMediaPlayer;
    public static final int IjkPlayer = PlayerEngine.IjkPlayer;

    public static final int VIEW_TYPE_SurfaceView = ContentView.VIEW_TYPE_SurfaceView;
    public static final int VIEW_TYPE_TextureView = ContentView.VIEW_TYPE_TextureView;
    public static final int VIEW_TYPE_GLSurfaceView = ContentView.VIEW_TYPE_GLSurfaceView;

    public static final int DIRECT = ContentView.DIRECT;
    public static final int SPHERE = ContentView.SPHERE;

    // 状态控制变量
    private boolean mSurfaceCreated = false;
    private boolean mMediaPerpared = false;
    private boolean mPlayWhenReady = true;
    private boolean mPlayBeforeSeek = false;

    // 成员变量
    private final Context mContext;
    private PlayerEngine mEngine;
    private final MediaParam mParam;
    private AudioFocusRequest mAudioFocusRequest;
    private float mVolume = 1; // [0.0, 1.0]

    // 播放器控件
    private final ViewGroup mContainer;
    private VideoView mVideoView;
    private ContentView mContentView;

    private final Handler mMainHandler;
    private Timer mBandwidthTimer;
    private BandwidthCallback mBandwidthCallback;

    public SimplePlayer(Context context, MediaParam param, ViewGroup container)  {
        mContext = context;
        mMainHandler = new Handler();
        mParam = param;
        mContainer = container;

        initVideoView();
        if (param.preload) {
            toggle();
        }
    }

    private PlayerEngine getCurrentEngine() {
        if (mEngine == null) {
            switch (mParam.enginetype) {
                case ExoPlayer:
                    mEngine = PlayerEngineFactory.CreateEngine(PlayerEngine.ExoPlayer, mContext);
                    break;
                case AndroidMediaPlayer:
                    mEngine = PlayerEngineFactory.CreateEngine(PlayerEngine.AndroidMediaPlayer, mContext);
                    break;
                case IjkPlayer:
                    mEngine = PlayerEngineFactory.CreateEngine(PlayerEngine.IjkPlayer, mContext);
                    break;
            }
            if (mEngine != null) {
                mEngine.setClient(new SimPlePlayerEngineClient());
                mEngine.setVolume(mVolume);
                if (mParam.viewtype == VIEW_TYPE_SurfaceView) {
                    mEngine.setSurfaceView(((SurfaceView)mContentView.getView()));
                    mSurfaceCreated = true;
                } else if (mParam.viewtype == VIEW_TYPE_TextureView) {
                    mEngine.setTextureView((TextureView)mContentView.getView());
                    mSurfaceCreated = true;
                }
            } else {
                onError();
            }
        }
        return mEngine;
    }

    private void initVideoView() {
        // 创建容纳 surface 的 ContentView
        switch (mParam.viewtype) {
            case VIEW_TYPE_SurfaceView:
                mContentView = ContentViewFactory.createContentView(
                        mContext, null,
                        ContentView.VIEW_TYPE_SurfaceView, ContentView.DIRECT);
                break;
            case VIEW_TYPE_TextureView:
                mContentView = ContentViewFactory.createContentView(
                        mContext, null,
                        ContentView.VIEW_TYPE_TextureView, ContentView.DIRECT);
                break;
            case VIEW_TYPE_GLSurfaceView:
                if (mParam.rendertype == DIRECT) {
                    mContentView = ContentViewFactory.createContentView(
                            mContext, new ContentViewListener(),
                            ContentView.VIEW_TYPE_GLSurfaceView, ContentView.DIRECT);
                } else {
                    mContentView = ContentViewFactory.createContentView(
                            mContext, new ContentViewListener(),
                            ContentView.VIEW_TYPE_GLSurfaceView, ContentView.SPHERE);
                }
                break;
        }

        mVideoView = new VideoView(mContext, this, mParam.displaymode);
        mVideoView.setContentView(mContentView.getView());
        mContainer.addView(mVideoView);
    }

    private void MaybePrepared() {
        if (!mSurfaceCreated || !mMediaPerpared) return;
        onPrepared();
    }

    public void toggle() {
        if (getCurrentState() == IDLE) {
            prepare();
            setPlayWhenReady(true);
        } else if (getCurrentState() == PREPARING) {
            setPlayWhenReady(true);
        } else if (getCurrentState() == PREPARED) {
            start();
        }

        if (getCurrentState() == PLAYING) {
            pause();
        } else if (getCurrentState() == PAUSE) {
            if (getDuration() != 0 && getCurrentPosition() >= getDuration()) {
                // 播放结束，重新播放
                seekTo(0);
            }
            resume();
        }
    }

    @Override
    protected void prepare() {
        super.prepare();
        getCurrentEngine().prepare(mParam.uri);
    }

    @Override
    protected void onPrepared() {
        super.onPrepared();
        if (mPlayWhenReady) {
            start();
        }
    }

    @Override
    protected void start() {
        super.start();
        resume();
    }

    @Override
    protected void resume() {
        if (!requestAudioFocus()) {
            LogUtil.e(TAG, "request audio fus failed");
            return;
        }
        getCurrentEngine().play();
        super.resume();
    }

    @Override
    protected void pause() {
        getCurrentEngine().pause();
        super.pause();
    }

    @Override
    public void stop() {
        abandonAudioFocus();
        stopCalculateBandwidth();
        super.stop();
    }

    @Override
    public void seekTo(long position) {
        position = Math.min(position, getDuration());
        mPlayBeforeSeek = isPlaying();
        super.seekTo(position);
        getCurrentEngine().seekTo(position);
    }

    @Override
    public boolean isPlaying() {
        if (getCurrentState() == PREPARING && mPlayWhenReady) {
            return true;
        }

        return getCurrentState() == PLAYING;
    }

    /**
     * 获取视频时长
     * @return 视频时长，单位:ms
     */
    @Override
    public long getDuration() { return getCurrentEngine().getDuration(); }

    /**
     * 获取当前播放位置
     * @return 当前位置，单位:ms
     */
    @Override
    public long getCurrentPosition() {
        return getCurrentEngine().getCurrentPosition();
    }

    public void setPlayWhenReady(boolean playWhenReady) {
        mPlayWhenReady = playWhenReady;
    }

    public int getVideoHeight() {
        return getCurrentEngine().getVideoHeight();
    }

    public int getVideoWidth() {
        return getCurrentEngine().getVideoWidth();
    }

    public int getCurrentDisPlayMode() {
        return mVideoView.getCurrentDisPlayMode();
    }

    public void switchDisplayModeTo(@DISPLAYMODE int mode) {
        mVideoView.switchDisplayModeTo(mode);
    }

    public synchronized void startCalculateBandwidth(long intervalMillis, BandwidthCallback callback) {
        if (mBandwidthTimer != null) return;

        mBandwidthCallback = callback;
        mBandwidthTimer = new Timer(() -> {
            if (mBandwidthCallback != null) {
                if (mEngine != null) {
                    mBandwidthCallback.onGetBandwidth(mEngine.getBandwidth() / (8 * 1024));
                } else {
                    mBandwidthCallback.onGetBandwidth(0);
                }
            }
        }, intervalMillis);
        mBandwidthTimer.start();
    }

    public synchronized void stopCalculateBandwidth() {
        if (mBandwidthTimer != null) {
            mBandwidthTimer.stop();
            mBandwidthTimer = null;
        }
        mBandwidthCallback = null;
    }

    private boolean isMainThread() {
        return Looper.myLooper() == Looper.getMainLooper();
    }

    private void postOnMainThread(Runnable runnable) {
        if (isMainThread()) {
            // 已经在主线程，直接运行
            runnable.run();
        } else {
            // 在子线程，抛到主线程去运行
            mMainHandler.post(runnable);
        }
    }

    // ---------------------------------------------------------------------------------------------
    // 音频焦点管理
    // https://developer.android.com/guide/topics/media-apps/audio-focus?hl=zh-cn#java
    private boolean requestAudioFocus() {
        if (mContext == null) return false;
        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        int ret;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (mAudioFocusRequest == null) {
                AudioAttributes playbackAttributes = new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_MEDIA)
                        .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
                        .build();
                mAudioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                        .setAudioAttributes(playbackAttributes)
                        .setAcceptsDelayedFocusGain(true)
                        .setOnAudioFocusChangeListener(this)
                        .build();
            }
            ret = audioManager.requestAudioFocus(mAudioFocusRequest);
        } else {
            ret = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        }
        return ret == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
    }

    private void abandonAudioFocus() {
        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (mAudioFocusRequest != null) {
                audioManager.abandonAudioFocusRequest(mAudioFocusRequest);
            }
        } else {
            audioManager.abandonAudioFocus(this);
        }
    }

    @Override
    public void onAudioFocusChange(int focusChange) {
        switch (focusChange) {
            case AudioManager.AUDIOFOCUS_GAIN:
                // 重新获取永久焦点，恢复音量
                getCurrentEngine().setVolume(mVolume);
                break;
            case AudioManager.AUDIOFOCUS_LOSS:
                // 永久丢失焦点，停止播放
                if (isPlaying()) {
                    toggle();
                }
                break;
            case  AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                // 暂时性失去焦点，降低音量
                getCurrentEngine().setVolume(mVolume / 2);
                break;
            default:
                break;
        }
    }
    // ---------------------------------------------------------------------------------------------

    // ---------------------------------------------------------------------------------------------
    // Listener 定义
    private class ContentViewListener implements ContentView.SurfaceListener {
        @Override
        public void onSurfaceCreate(@NonNull Surface surface) {
            postOnMainThread(() -> {
                LogUtil.i(TAG, "SurfaceCreated " + surface.toString());
                mSurfaceCreated = true;
                //将播放器捕捉的画面展示到SurfaceView画面上
                getCurrentEngine().setSurface(surface);
                MaybePrepared();
            });
        }

        @Override
        public void onSurfaceDestroy(@NonNull Surface surface) {
            postOnMainThread(() -> {
                LogUtil.i(TAG, "SurfaceDestroy");
                getCurrentEngine().setSurface(null);
            });
        }

        @Override
        public void onSurfaceHolderCreate(@NonNull SurfaceHolder holder) {
            postOnMainThread(() -> {
                LogUtil.i(TAG, "SurfaceHolderCreate " + holder.toString());
                mSurfaceCreated = true;
                //将播放器捕捉的画面展示到SurfaceView画面上
                getCurrentEngine().setDisplay(holder);
                MaybePrepared();
            });
        }
    }

    private class SimPlePlayerEngineClient extends PlayerEngineClient {
        @Override
        public void onSeekComplete() {
            if (mPlayBeforeSeek) {
                resume();
            } else {
                pause();
            }
        }

        @Override
        public void onPrepared() {
            LogUtil.d(TAG, "视频资源已就绪");
            mMediaPerpared = true;
            MaybePrepared();
        }

        @Override
        public void onPlaybackComplete() {
            pause();
        }

        @Override
        public void onError() {
            SimplePlayer.this.onError();
        }

        @Override
        public void onVideoSizeChanged(int width, int height) {
            mContentView.onContentSizeChanged(width, height);
        }

        @Override
        public void onBufferingStart() {
            SimplePlayer.this.notifyBufferingStart();
        }

        @Override
        public void onBufferingEnd() {
            SimplePlayer.this.notifyBufferingEnd();
        }
    }
    // ---------------------------------------------------------------------------------------------
}
